package hoe;

import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicReference;
import javax.servlet.AsyncContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * Felhasználó.
 *
 * @author imruf84
 */
public class User {

    /**
     * Felhasználói név session azonosítójának neve.
     */
    public static String USER_NAME_SESSION_KEY = "user";
    /**
     * Hard bit long pollinghoz.
     */
    private final AtomicReference<HttpServletResponse> response = new AtomicReference<>(null);
    private final AtomicReference<AsyncContext> context = new AtomicReference<>(null);
    /**
     * Session azonosító.
     */
    private final String sessionId;

    /**
     * Felhasználó neve.
     */
    private final String userName;
    /**
     * Küldendő üzenetek.
     */
    private final LinkedList<String> messages = new LinkedList<>();

    /**
     * Konstruktor.
     *
     * @param sessionId session azonosító
     * @param userName felhasználó neve
     */
    public User(final String sessionId, final String userName) {
        this.sessionId = sessionId;
        this.userName = userName.replaceAll("\"", "\\\\\"").replaceAll("'", "\\\\'");
    }

    /**
     * Session azonosító lekérdezése.
     *
     * @return session azonosító
     */
    public String getSessionId() {
        return sessionId;
    }

    /**
     * Felhasználó hitelességének a vizsgálata.
     *
     * @param request kérelem
     * @return igaz esetén a felhasználó hiteles, egyébként nem
     */
    public boolean isValid(final HttpServletRequest request) {
        HttpSession session = request.getSession();
        String lUserName = (String) session.getAttribute(USER_NAME_SESSION_KEY);

        if (null == lUserName) {
            return false;
        }

        return lUserName.equals(getUserName());
    }

    /**
     * Felhasználó nevének a lekérdezése.
     *
     * @return felhasználó neve
     */
    public String getUserName() {
        return userName;
    }

    /**
     * Üzenet küldése a felhasználónak.
     * @param msg üzenet
     * @throws IOException kivétel
     */
    public void sendMessage(final String msg) throws IOException {

        // Üzenet tárolása.
        synchronized (messages) {
            messages.add(msg);
        }

        // Üzenet(ek) küldése.
        flushMessages();
    }

    /**
     * Aszinkron szál tárolása (long polling válasz csatorna).
     * 
     * @param c csatorna
     * @param r válasz
     * @throws IOException kivétel
     */
    public void storeAsyncContext(final AsyncContext c, final HttpServletResponse r) throws IOException {

        // Ha van már tárolva, akkor töröljük.
        synchronized (context) {
            if (null != context.get()) {
                // Szál futásának a befejezése.
                context.get().complete();
            }

            // Majd tároljuk az újat.
            synchronized (response) {
                response.set(r);
                context.set(c);

                // Ha van szál megadva, akkor lefuttatjuk.
                if (null != c && null != r) {
                    context.get().start(() -> {
                    });
                }
            }
        }
        
        // Majd továbbítjuk a felhalmozott üzeneteket.
        flushMessages();
    }

    /**
     * Üzenetek kiküldése.
     * 
     * @throws IOException kivétel
     */
    private void flushMessages() throws IOException {

        synchronized (messages) {

            // Ha nincs küldendő üzenet, akkor kilépünk.
            if (messages.isEmpty()) {
                return;
            }

            // Ha nincs aktív nyitott csatorna, akkor kilépünk.
            synchronized (context) {
                if (null == context.get() || null == response.get()) {
                    return;
                }
                
            
                // Üzenetek összefűzése.
                String s = Arrays.toString(messages.toArray());
                messages.clear();
                
                // Küldés.
                response.get().setContentType("text/json");
                response.get().setCharacterEncoding("UTF-8");
                response.get().setStatus(HttpServletResponse.SC_OK);
                response.get().getWriter().append(s);
                
                // Válaszcsatorna zárása.
                try {
                    context.get().complete();
                } catch (IllegalStateException ex){}
                context.set(null);
                response.set(null);
                
            }

            
        }

    }

}
